#include "../../common/RuleSet.h"
#include "serverset.h"
#include "webservicetool.h"
#include "..\common\DBInterface.h"
#include <iostream>
#include "wsclient.h"
#include "udpserver.h"
using namespace std;

//#include "map.h"
#define  RULESETFILE _T("Set\\ruleset.xml") 
#define SERVER_PORT 5001

CRuleSet g_RULESET;

CRuleSet::CRuleSet(void)
{
}
CRuleSet::~CRuleSet(void)
{
}


void CRuleSet::GetRuleFrmDB()
{
	CDBInterface* pdbinterface= new CDBInterface("..\\mydb.db");
	pdbinterface->open();
	pdbinterface->loadAllRuleFrmDB();
	pdbinterface->close();
}
#if 0		//working 
void CRuleSet::delRuleFrmDB(string rulename)
{

	CDBInterface* pdbinterface= new CDBInterface("..\\mydb.db");
	string delsql="";
	del
	pdbinterface->open();
	pdbinterface->
}
#endif


void CRuleSet::StoreRule2DB(string rule_name,CRule & rule)
{
	CDBInterface* pdbInterface=new CDBInterface("..\\mydb.db");
	pdbInterface->open();
	string sqlCreatTable="CREATE TABLE rule_tbl(\
						 ruleName CHAR(15) NOT NULL UNIQUE,\
						 time  CHAR(12),\
						 event CHAR(100),\
						 condition CHAR(20),\
						 cmptype  CHAR(2),\
						 action CHAR(100),\
						 priority CHAR(4),\
						 owner CHAR(20)\
						 );";

	int ret=pdbInterface->createTable(sqlCreatTable);
	if(ret!=0)
	{
		std::cout<<"creat table failed"<<endl;
	}
	pdbInterface->SaveOneRule(rule_name ,rule);
	pdbInterface->close();
}

int CRuleSet::add_rule(string name,CRule rule)
{
	map<string,CRule>::iterator iter;
	iter=m_Ruleset.find(name);
	if(iter==m_Ruleset.end())//can not find 
	{
		m_Ruleset.insert(pair<string,CRule>(name,rule));
		return 0;
	}	
	else return -1;
}



string CRuleSet::del_rule(string name)
{
	map<string,CRule>::iterator iter=m_Ruleset.find(name);
	string ret="";
	if(iter==m_Ruleset.end())
		ret+= "no such rule";
	else
	{
		m_Ruleset.erase(iter);
		ret+= "map clear\n";
	}
	CDBInterface* pdbInterface=new CDBInterface("..\\mydb.db");
	pdbInterface->open();
	
	int delret=pdbInterface->delOneRec("rule_tbl","ruleName",name);
	if(delret==0)
	{
		ret+="DB clear\n";
	}
	return ret;
}

void CRuleSet::del_neighbour_ruleset(string name)
{
	string url="";
	vector<string>::iterator iter;
	vector<string> * neighbourIP=UDP_server::GetNBContainer();
	for(iter=neighbourIP->begin();iter!=neighbourIP->end();iter++)
	{
		url+="http://";
		url+=*iter;
		url+=":5001/del_one_rule";
		wsClient::getGclient()->Callwebservices(url, name);
	}
}
//ruleset run follow steps:
/*
	step1: run every event and compare the condition and store the result:ready or not
	step2: get the rule which are ready and have the highest prority
	step3: run the action chosen
	step4: make the rule to sleep
*/

void CRuleSet::refresh_rule_staus()
{
	map<string,CRule>::iterator index=m_Ruleset.begin();
	for(index=m_Ruleset.begin();index!=m_Ruleset.end();index++)
	{	
		int ret=index->second.do_event();
		if(ret==MACHSUCC)
		{	
			index->second.active=true;  //rule is ready
		}
	}
}

//get the highest and active rule to act .the rule must be active  
//edit by ljy if return null meas no active rules
map<string,CRule>::iterator CRuleSet::GethighestRule()
{
	if(m_Ruleset.empty())
	{
		return NULL;
	}
	map<string,CRule>::iterator index=m_Ruleset.begin();
	map<string,CRule>::iterator maxindex=m_Ruleset.begin();
	for(index=m_Ruleset.begin();index!=m_Ruleset.end();index++)
	{
		if(index->second.active==true)
		{
			if((index->second.pri)>=maxindex->second.pri)
			{
				maxindex=index;
				
			}
		}
	}
	if( maxindex==m_Ruleset.begin()&&maxindex->second.active==false)//no active rule to run
	{
		return NULL;
	}
	else return maxindex;
}
//edit by ljy  to see if all rule is sleeped.
bool CRuleSet::Is_Ruleset_all_sleep()
{
	return true;
}


//return ture if empty
bool CRuleSet::IsEmpty()
{
	return m_Ruleset.empty();
}

actionType  getActionType(string express)
{
	int index=express.find_first_of('(');
	string funname  = express.substr(0,index);
	if(funname == FNAME_CALWS)
	{
		return CALLWS;
	}
	else
	{
		return ACTYPE_UNKNOW;
	}

}

//decode somthing like callwebservice(http://getval,110)  
void De_function_name(string express,string & funname)
{
	string::size_type index=express.find_first_of('(');
	funname=express.substr(0,index);
}
//judge something like callwebservice(http://getval,110) can be suported 
bool CRuleSet::issupport(string express)
{
	string funname;
	De_function_name(express,funname);
	if(funname=="callwebservice")
	{
		return true;
	}
	else 
	{
		return false;
	}
}
//get url and cmd from the para 
void De_callweb_para(string funcall_express,string & url,string& cmd)
{
	string::size_type indexhead=funcall_express.find_first_of('(');
	string::size_type indexend=funcall_express.find_first_of(')');
	string para =funcall_express.substr(indexhead+1,indexend-indexhead-1);
	string::size_type index2=para.find_first_of(',');
	url=para.substr(0,index2);
	cmd=para.substr(index2+1,para.length());

}



int CRule::getMachResult()
{
	if(str_condition_dest == "")
	{
		return MACHSUCC;
	}
	int ret=MACHFAIL;
	RuleCmpType cmptype=getCompareType();
	switch(cmptype)
	{
	case EQAUL:
		if(str_condition == str_condition_dest )
		{
			ret=  MACHSUCC;
		}
		break;
	case RET_BIGERTHAN_DST:
		if(atoi(str_condition.c_str())>atoi(str_condition_dest.c_str()))
		{
			ret = MACHSUCC;
		}	
		break;
	case RET_LITERTHAN_DST:
		if(atoi(str_condition.c_str())<atoi(str_condition_dest.c_str()))
		{
			ret = MACHSUCC;
		}
		break;
	default:
		ret= MACHFAIL;
		break;
	}
	return ret;
}

int CRule::do_event(void)
{
	time_t timenow=time(NULL);
	if("" == str_time)
	{
		str_time="1";
	}
	if(int val= timenow - getLastActiontime()<atoi(str_time.c_str()))
	{
		return NOTIMETOMACH;	
	}
	actionType actype= getActionType(str_event);
	string url;
	string cmd;
	int ret =MACHFAIL;
	int index=0;
	switch(actype)
	{
		case CALLWS:
			// str_para_for_event is something like http://localhost/longetpump,123
			De_callweb_para(str_event,url,cmd);
			str_condition=wsClient::getGclient()->Callwebservices(url,cmd);
			ret=getMachResult();
			break;
		default:
			ret =  MACHFAIL;
			break;
	}
	return ret;
}



RuleCmpType CRule::getCompareType()
{
	if(str_Comparetype == "=")
	{
		return EQAUL;
	}
	else if(str_Comparetype == CMPSTRING_BIGGER)
	{
		return RET_BIGERTHAN_DST;
	}
	else if(str_Comparetype == CMPSTRING_LESS)
	{
		return RET_LITERTHAN_DST;
	}
	else
		return CMPTYPE_UNKNOW;
}

/**************************************************************
cmd of actioncanbe  cmd=insert;itemName=xxx,itemValue=$eventResult;
**************************************************************/
void CRule::do_action(void)
{
	string fun_name;
	string url;
	string cmd;
	string wsret;
	De_function_name(str_action,fun_name);
	// str_para_for_event is something like http://localhost/longetpump,123
	De_callweb_para(str_action,url,cmd);
	int index =cmd.find(EVENTRESULT);
	if(string::npos != index)
	{
		cmd.replace(index,strlen(EVENTRESULT),str_condition);
	}
    //cmd+=str_condition;
	//cmd+=";";
	if(fun_name=="callwebservice")
	{
		wsret+=wsClient::getGclient()->Callwebservices( url, cmd);
	}
	lastActionTime  =time(NULL);
}



void CRule::create_eca_rule(UINT priority,string time,string event,
	string condition_dest,string action,string owner,string compare_type)
{
	pri=priority;
	str_time=time;
	str_event=event;
	str_condition_dest=condition_dest;
	str_action=action;
	str_Comparetype =   compare_type;
	string HostIP=CServerSet::gOnly().getHostIP();
	if(owner==""||owner=="localhost")
	{
		str_owner=HostIP;
	}
	else
	{
		str_owner=owner;
	}
	active=false;
}
void CRule::exe_eca_rule()
{
	do_action();
	active=false;	
}

